package com.lcf.user.config;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * RECORD
 * 每处理一条commit一次
 * BATCH(默认)
 * 每次poll的时候批量提交一次，频率取决于每次poll的调用频率
 * TIME
 * 每次间隔ackTime的时间去commit
 * COUNT
 * 累积达到ackCount次的ack去commit
 * COUNT_TIME
 * ackTime或ackCount哪个条件先满足，就commit
 * MANUAL
 * listener负责ack，但是背后也是批量上去
 * MANUAL_IMMEDIATE
 * listner负责ack，每调用一次，就立即commit
 */
@Component
@EnableKafka
//@ConfigurationProperties(prefix = "portrait.verify")
public class KafkaConsumerConfig {
    @Value("${spring.kafka.bootstrap-servers}")
    private String servers;

    //enable.auto.commit参数设置成true。那么offset交给kafka来管理，offset进行默认的提交模式。
    //enable.auto.commit参数设置成false。那么就是Spring来替为我们做人工提交，从而简化了人工提交的方式
    @Value("${spring.kafka.consumer.enable-auto-commit}")
    private boolean enableAutoCommit;

    @Value("${spring.kafka.consumer.session-timeout}")
    private String sessionTimeout;

    @Value("${spring.kafka.consumer.auto-commit-interval}")
    private String autoCommitInterval;

    @Value("${spring.kafka.consumer.group-id}")
    private String groupId;

    @Value("${spring.kafka.consumer.auto-offset-reset}")
    private String autoOffsetReset;

    @Bean("listenerAckFactory")
    public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>> kafkaListenerContainerFactory(ConsumerFactory<String, String> consumerFactory) {
        ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory);
        factory.getContainerProperties().setPollTimeout(1500);
        //配置手动提交offset
        factory.getContainerProperties().setAckMode((ContainerProperties.AckMode.MANUAL_IMMEDIATE));
        factory.getContainerProperties().setAckOnError(false);
//        #消费者并发启动个数（对应分区个数）每个listener方法,将启动器的并发提高到和分区数一致
        factory.setConcurrency(2);

        //禁止自动启动,用于持久化操作，可先将消息都发送至broker，然后在固定的时间内进行持久化，有丢失消息的风险
        //factory.setAutoStartup(false);


        return factory;
    }

    /**
     * 配置批量提交监听
     *
     * @return
     */
    @Bean("batchListenerFactory")
    KafkaListenerContainerFactory<?> listenerAckFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(new DefaultKafkaConsumerFactory(customerConfigs()));
        // 这个就是用来控制是否批量处理
        //factory.setBatchListener(true);


        return factory;
    }

    @Bean
    public ConsumerFactory<String, String> consumerFactory() {
        return new DefaultKafkaConsumerFactory(customerConfigs());
    }

    public Properties customerConfigs() {
        Properties props = new Properties();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit);//自动位移提交
        props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval);//自动位移提交间隔时间
        //props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sessionTimeout);//消费组失效超时时间
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);//位移丢失和位移越界后的恢复起始位置
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class.getName());
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class.getName());

        return props;
    }

}
